-- This is the permissive BSD liscense
-- * Copyright (c) 2007, Chris Holland
-- * All rights reserved.
-- *
-- * Redistribution and use in source and binary forms, with or without
-- * modification, are permitted provided that the following conditions are met:
-- *     * Redistributions of source code must retain the above copyright
-- *       notice, this list of conditions and the following disclaimer.
-- *     * Redistributions in binary form must reproduce the above copyright
-- *       notice, this list of conditions and the following disclaimer in the
-- *       documentation and/or other materials provided with the distribution.
-- *     * Neither the name of the <organization> nor the
-- *       names of its contributors may be used to endorse or promote products
-- *       derived from this software without specific prior written permission.
-- *
-- * THIS SOFTWARE IS PROVIDED BY Chris Holland ``AS IS'' AND ANY
-- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-- * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
-- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-- Some of the code is copied from Bilzards' PetActionBarFrame.lua file noted below

local PRE_DBG = ""

local function debug(msg)
	if (DEFAULT_CHAT_FRAME ~= nil) then
		if (PRE_DBG ~= "") then
			DEFAULT_CHAT_FRAME:AddMessage(PRE_DBG);
		end
		DEFAULT_CHAT_FRAME:AddMessage(msg);
	else
		PRE_DBG = PRE_DBG .. msg .. "\n";
	end
end

ACTIONPETBAR_SavedVars = {};

local buttons = {}
local RespaceButtons = nil
local PetBarConfigure = nil
local RestoreRegState = nil
local RestoreLockState = nil

local function GetSavedVar(name,def)
	local key = GetRealmName() .. "_" .. UnitName("player") .. "_" .. name;
	
	if (ACTIONPETBAR_SavedVars[key] ~= nil) then
		return ACTIONPETBAR_SavedVars[key];
	end
	return def;
end

local function SetSavedVar(name,val)
	local key = GetRealmName() .. "_" .. UnitName("player") .. "_" .. name;
	ACTIONPETBAR_SavedVars[key] = val;
end

local PETBAR_UPDATE = .250

local function petButtonUpdate(self, elapsed)
	self.lastPetbarUpdate = self.lastPetbarUpdate + elapsed
	
	if self.lastPetbarUpdate > PETBAR_UPDATE then
		local buttonName = "pb_pabBtn" .. self:GetID();
		--debug("Button name is " .. buttonName)
		petActionButton = _G[buttonName];
		petActionIcon = _G[buttonName.."Icon"];
		petAutoCastableTexture = _G[buttonName.."AutoCastable"];
		petAutoCastShine = _G[buttonName.."Shine"];
		local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(self:GetID());
		if ( not isToken ) then
			petActionIcon:SetTexture(texture);
			petActionButton.tooltipName = name;
		else
			petActionIcon:SetTexture(getglobal(texture));
			petActionButton.tooltipName = getglobal(name);
		end
		petActionButton.isToken = isToken;
		petActionButton.tooltipSubtext = subtext;
		if ( isActive ) then
			petActionButton:SetChecked(1);
		else
			petActionButton:SetChecked(0);
		end
		if ( autoCastAllowed ) then
			petAutoCastableTexture:Show();
		else
			petAutoCastableTexture:Hide();
		end
		if ( autoCastEnabled ) then
			AutoCastShine_AutoCastStart(petAutoCastShine);
		else
			AutoCastShine_AutoCastStop(petAutoCastShine);
		end
		if ( name and InCombatLockdown() ~= 1 ) then
			petActionButton:Show();
		end
		if ( texture ) then
			if ( GetPetActionSlotUsable(self:GetID()) ) then
				SetDesaturation(petActionIcon, nil);
			else
				SetDesaturation(petActionIcon, 1);
			end
			petActionIcon:Show();
			petActionButton:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2");
		else
			petActionIcon:Hide();
			petActionButton:SetNormalTexture("Interface\\Buttons\\UI-Quickslot");
		end
		
		cooldown = getglobal(buttonName.."Cooldown")
		--print(tostring(cooldown))
		local start, duration, enable = GetPetActionCooldown(self:GetID());
		CooldownFrame_SetTimer(cooldown, start, duration, enable);
	end
end

local petWatchDriver = CreateFrame("Button","PetWatchDriver",nil,nil);
petWatchDriver:SetParent(UIParent);
petWatchDriver:SetMovable(1);
petWatchDriver:EnableMouse(1);
petWatchDriver:SetToplevel(1);
petWatchDriver:ClearAllPoints();
petWatchDriver:SetWidth(32);
petWatchDriver:SetHeight(32);
petWatchDriver:SetPoint("CENTER",UIParent,"CENTER",0,0);
petWatchDriver:SetFrameStrata("LOW");
petWatchDriver:RegisterForDrag("LeftButton");
petWatchDriver:RegisterForClicks("RightButtonUp");
petWatchDriver:SetScript("OnDragStart", function(this,btn)
											if (GetSavedVar("locked",0) == 0) then
												this:StartMoving();
											end
										end);

petWatchDriver:SetScript("OnDragStop", function(this)
											this:StopMovingOrSizing();
										end);
petWatchDriver:RegisterEvent("ADDON_LOADED");
petWatchDriver:SetScript("OnEvent", function (self,event,...)
										if (event == "ADDON_LOADED" and select(1,...) == "ActionPetbar") then
											local val = GetSavedVar(petWatchDriver:GetName() .. "_scale",1)
											petWatchDriver:SetScale(val)
											RespaceButtons()
											RestoreRegState()
											RestoreLockState()
										end
									end)




petWatchDriver:SetBackdropColor(1,1,1,1);
local t = petWatchDriver:CreateTexture(nil,"BACKGROUND");
t:SetTexture(.5,.5,.5,.4);
t:SetAllPoints(petWatchDriver);
petWatchDriver.bk = t;
petWatchDriver:SetAttribute("unit","pet");
RegisterUnitWatch(petWatchDriver);

local NUM_PET_ACTION_BUTTONS = 10

local offsetFrom = petWatchDriver
for i = 1,NUM_PET_ACTION_BUTTONS, 1 do
	local btn = CreateFrame("CheckButton","pb_pabBtn" .. i,petWatchDriver,"PetActionButtonTemplate");
	btn:SetID(i);
	btn:SetPoint("LEFT",offsetFrom,"RIGHT",GetSavedVar("spacing",1),0);
	btn:SetScript("OnUpdate", petButtonUpdate);
	btn.lastPetbarUpdate = 0;
	btn:Show();
	buttons[i] = btn;
	offsetFrom = btn;
end

RespaceButtons = function()
	local offset = nil
	
	for q,btn in ipairs(buttons) do
		if offset then
			if (GetSavedVar("dir","horiz") == "vert") then
				btn:SetPoint("TOPLEFT",offset,"BOTTOMLEFT",0,-GetSavedVar("spacing",1))
			else
				btn:SetPoint("TOPLEFT",offset,"TOPRIGHT",GetSavedVar("spacing",1),0)
			end
		else
			if (GetSavedVar("dir","horiz") == "vert") then
				btn:SetPoint("TOPLEFT",petWatchDriver,"BOTTOMLEFT",0,0)
			else
				btn:SetPoint("TOPLEFT",petWatchDriver,"TOPRIGHT",0,0)
			end
		end
		offset = btn
	end
end

local apBar_LastScale = nil;

local function pad_config_onUpdate(self,elapsed)
	local newScale = self.slider:GetValue()/100;
	if (apBar_LastScale == nil) then
		apBar_LastScale = self.control_parent:GetScale();
	end
	if (newScale ~= apBar_LastScale) then
		self.slider.text:SetText("Scale " .. newScale*100 ..  "%");
		
		local setL = floor(self.control_parent:GetLeft() * self.control_parent:GetScale() +0.5);
		local setT = floor(self.control_parent:GetTop() * self.control_parent:GetScale() + 0.5); -- note this is the distance from the top of the window to the bottom of the screen
		-- so to get the thing in TL respective coords UIParent:GetHeight()-setT should be the distance from the top
		setT = UIParent:GetHeight() - setT;
		
		self.control_parent:SetScale(newScale);
		self.control_parent:ClearAllPoints();
		self.control_parent:SetPoint("TOPLEFT",UIParent,"TOPLEFT", setL/self.control_parent:GetScale(),-setT/self.control_parent:GetScale());
		
		SetSavedVar(self.control_parent:GetName() .. "_scale",newScale);
		apBar_LastScale = newScale
	end
end

local op_LastScale = nil

local function options_TrackScale(self,elapsed)
	if (op_LastScale == nil) then
		op_LastScale = self.control_parent:GetScale();
	end
	
	if (self.control_parent:GetScale() ~= op_LastScale) then
		op_LastScale = self.control_parent:GetScale()
		
		local pX = self.control_parent:GetLeft() * self.control_parent:GetScale();
		local pY = self.control_parent:GetScale() * self.control_parent:GetTop();
		local pH = self.control_parent:GetHeight() * self.control_parent:GetScale();
		self:SetPoint("TOPLEFT",UIParent,"TOPLEFT", pX, -(self:GetParent():GetTop() - pY)  - pH);
	end
end

local function options_onUpdate(self,elapsed)
	local num = self:GetNumber()
	if (num ~= GetSavedVar("spacing",1)) then
		SetSavedVar("spacing",num);
		RespaceButtons();
	end
end

local function options_onEnter(self)
	self:ClearFocus();
end

local function createConfigScale(name, control_parent)
	local cfg_pad = CreateFrame("Frame",name, UIParent, nil);
	cfg_pad.control_parent = control_parent;
	cfg_pad:SetWidth(250);
	cfg_pad:SetHeight(70);
	local bg = cfg_pad:CreateTexture(nil, "BACKGROUND");
	bg:SetTexture(0.5,0.5,0.5,0.5);
	bg:SetAllPoints(cfg_pad);
	
	cfg_pad:SetScript("OnUpdate",pad_config_onUpdate);
--	cfg_pad:SetPoint("TOPLEFT",UIParent,"TOPLEFT",control_parent:GetLeft(),-(cfg_pad:GetParent():GetTop() - control_parent:GetTop()) + cfg_pad:GetHeight());
	cfg_pad:Hide();

	
	local lbl = cfg_pad:CreateFontString(nil, "TEXT");
	lbl:SetFontObject(GameFontNormalSmall);
	lbl:SetPoint("BOTTOMLEFT", cfg_pad, "TOPLEFT", 5, -10);
	lbl:SetText("Configuration");
	
	cfg_pad.slider = CreateFrame("Slider",name.."_scale", cfg_pad, "OptionsSliderTemplate");
	cfg_pad.slider:SetPoint("TOPLEFT",cfg_pad,"TOPLEFT",25,-20);
	cfg_pad.slider:SetWidth(cfg_pad:GetWidth() - 50);
	cfg_pad.slider:SetOrientation("HORIZONTAL");
	cfg_pad.slider:SetMinMaxValues(50,200);
	cfg_pad.slider:SetValue(control_parent:GetScale() * 100);
	cfg_pad.slider:SetValueStep(10);
	cfg_pad.slider.text = getglobal(cfg_pad.slider:GetName() .. "Text");
	cfg_pad.slider.text:SetText("Scale " .. cfg_pad.slider:GetValue() ..  "%");
	return cfg_pad;
end

local function createOptionsFrame(name, parent)
	local container = CreateFrame("Frame",name,UIParent)
	container:SetWidth(100);
	container:SetHeight(50);
	container.control_parent = parent;
	container:SetScript("OnUpdate",options_TrackScale);
	container:Hide();
	
	local bk = container:CreateTexture(nil, "BACKGROUND");
	bk:SetTexture(0.5,0.5,0.5,0.5);
	bk:SetAllPoints(container);
	
	local fstr = container:CreateFontString(nil,"ARTWORK","GameFontHighlight");
	fstr:SetWidth(50);
	fstr:SetHeight(25);
	fstr:SetPoint("TOPLEFT", container, "TOPLEFT")
	fstr:SetText("Spacing")
	
	local frame = CreateFrame("EditBox",nil,container,nil)
	frame.control_parent = parent;
	frame:SetWidth(30);
	frame:SetHeight(20);
	frame:SetPoint("TOPRIGHT", container, "TOPRIGHT")

	local bg = frame:CreateTexture(nil, "BACKGROUND");
	bg:SetTexture(0.5,0.5,0.5,0.5);
	bg:SetAllPoints(frame);
	
	frame:SetNumeric(true);
	frame:SetText(GetSavedVar("spacing",1));
	frame:SetScript("OnTextChanged",options_onUpdate);
	frame:SetMaxLetters(3);
	frame:SetTextInsets(1,1,1,1)
	frame:SetMultiLine(false)	
	frame:SetAutoFocus(false)
	frame:SetFontObject(ChatFontNormal)
	
	frame:SetScript("OnEnterPressed",options_onEnter);
	
	local done = CreateFrame("Button",nil,container,"OptionsButtonTemplate")
	done:SetWidth(50)
	done:SetHeight(25)
	done:SetText("Done")
	done:SetNormalFontObject(GameFontNormalSmallLeft)
	done:SetPoint("BOTTOM",container,"BOTTOM")
	done:SetScript("OnClick",PetBarConfigure)
	
	return container;
end

local configFrame = nil;
local optionsFrame = nil;

PetBarConfigure = function ()
	if not configFrame then
		configFrame = createConfigScale("CFG_ActionPetBar",petWatchDriver);
	end
	
	if not optionsFrame then
		optionsFrame = createOptionsFrame("CFG_APB_Options",petWatchDriver);
	end
	
	if configFrame:IsVisible() then
		configFrame:Hide();
	else
		if not petWatchDriver:IsVisible() then
			petWatchDriver:Show();
		end
		local pX = configFrame.control_parent:GetLeft() * configFrame.control_parent:GetScale();
		local pY = configFrame.control_parent:GetScale() * configFrame.control_parent:GetTop();
		configFrame:SetPoint("TOPLEFT",UIParent,"TOPLEFT", pX, -(configFrame:GetParent():GetTop() - pY)  + configFrame:GetHeight());
		configFrame:Show();
	end
	
	if optionsFrame:IsVisible() then
		optionsFrame:Hide();
	else
		local pX = optionsFrame.control_parent:GetLeft() * optionsFrame.control_parent:GetScale();
		local pY = optionsFrame.control_parent:GetScale() * optionsFrame.control_parent:GetTop();
		local pH = optionsFrame.control_parent:GetHeight() * optionsFrame.control_parent:GetScale();
		local pW = optionsFrame.control_parent:GetWidth() * optionsFrame.control_parent:GetScale();
		
		if (GetSavedVar("dir","horiz") == "vert") then
			optionsFrame:SetPoint("TOPLEFT",UIParent,"TOPLEFT", pX - optionsFrame:GetWidth(), -UIParent:GetHeight()+pY);
			optionsFrame:Show();
		else
			optionsFrame:SetPoint("TOPLEFT",UIParent,"TOPLEFT", pX, -(optionsFrame:GetParent():GetTop() - pY)  - pH);
			optionsFrame:Show();
		end
	end
	
end

local function WatchPet()
	SetSavedVar("reg",1)
	petWatchDriver:SetAttribute("unit","pet");
end

local function WatchPlayer()
	SetSavedVar("reg",0)
	petWatchDriver:SetAttribute("unit","player");
	petWatchDriver:Show();
end

RestoreRegState = function ()
	if (GetSavedVar("reg",1) == 1) then
		WatchPet()
	else
		WatchPlayer()
	end
end

local function LockBar()
	SetSavedVar("locked",1)
	petWatchDriver.bk:SetTexture(.5,.5,.5,0)
end

local function UnlockBar()
	SetSavedVar("locked",0)
	petWatchDriver.bk:SetTexture(.5,.5,.5,.4)
end

RestoreLockState = function ()
	if (GetSavedVar("locked",1) == 1) then
		LockBar()
	else
		UnlockBar()
	end
end

local function petBarCmd(cmd)
	debug("Got command: " .. cmd)
	if (cmd == "cfg") then
		PetBarConfigure();
	elseif (cmd == "unreg") then
		debug("Unregistering, and showing");
		WatchPlayer()
	elseif (cmd == "reg") then
		debug("Registering");
		WatchPet()
	elseif (cmd == "reset") then
		debug("Resetting position")
		petWatchDriver:ClearAllPoints();
		petWatchDriver:SetWidth(32);
		petWatchDriver:SetHeight(32);
		petWatchDriver:SetScale(1);
		petWatchDriver:SetPoint("CENTER",UIParent,"CENTER",0,0);
		SetSavedVar(petWatchDriver:GetName() .. "_scale",1);
	elseif (cmd == "check") then
		local setL = petWatchDriver:GetLeft();
		local setT = petWatchDriver:GetTop();
		debug("Left: " .. setL .. " Top: " .. setT .. " scale: " .. petWatchDriver:GetScale() .. " LeftS: " .. setL*petWatchDriver:GetScale() .. " TopS: " .. setT*petWatchDriver:GetScale())
	elseif (cmd == "lock") then
		LockBar()
	elseif (cmd == "unlock") then
		UnlockBar()
	elseif (cmd == "horiz") then
		SetSavedVar("dir","horiz")
		RespaceButtons()
	elseif (cmd == "vert") then
		SetSavedVar("dir","vert")
		RespaceButtons()
	else
		debug("/apbar cfg    , to toggle the configuration mode, or right click the dragging area.");
		debug("       unreg  , to un register it from watch the pet to allow movement without a pet.");
		debug("       reg    , to re register it to the pet and make it follow the pets existance.");
		debug("       lock   , to lock the bar and make it not be-able to be mouse dragged.");
		debug("       unlock , allow mouse movement.");
		debug("       horiz  , will make the bar render horizontally.");
		debug("       vert   , will make the bar render vertically.");
		debug("/apbar help ,to see this help.");
		
		local lockedStatus = nil;
		if (GetSavedVar("locked",0) == 1) then
			lockedStatus = "Locked: true"
		else
			lockedStatus = "Locked: false"
		end
		
		local regStatus
		if (GetSavedVar("reg",1) == 1) then
			regStatus = "Watching: Pet"
		else
			regStatus = "Watching: Nothing"
		end
		
		debug("Current status; " .. lockedStatus .. " " .. regStatus)
	end
end

SlashCmdList["ACTIONPETBAR"] = petBarCmd;
SLASH_ACTIONPETBAR1 = "/apbar"

-- Setup right click to do configuring on the background

petWatchDriver:RegisterForClicks("RightButtonUp");
petWatchDriver:SetScript("OnClick", function (self,event,...)
										PetBarConfigure();
									end );

debug("/apbar help, for config options");
